package com.snail.utils;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 订单和退款ID生成器
 * 自动包含ID生成时的实时年月日，通过前缀区分订单和退款
 */
public class DynamicDateOrderRefundIdGenerator {
    // 订单ID前缀
    private static final String ORDER_PREFIX = "ORD";
    // 退款ID前缀
    private static final String REFUND_PREFIX = "REF";

    // 日期格式器：生成实时的年月日（8位数字）
    private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyyMMdd");

    // 机器ID（0-31之间，支持32台机器）
    private final int machineId;

    // 序列号（同一秒内自增，0-999）
    private int sequence = 0;

    // 上一次生成ID的时间戳（毫秒）
    private long lastTimestamp = 0;

    // 上一次生成ID的日期字符串（用于跨天检测）
    private String lastDateStr;

    // 线程锁保证线程安全
    private final Lock lock = new ReentrantLock();

    /**
     * 构造函数
     * @param machineId 机器ID（0-31）
     */
    public DynamicDateOrderRefundIdGenerator(int machineId) {
        if (machineId < 0 || machineId > 31) {
            throw new IllegalArgumentException("机器ID必须在0-31之间");
        }
        this.machineId = machineId;
        // 初始化最后日期为当前日期
        this.lastDateStr = DATE_FORMAT.format(new Date());
    }

    /**
     * 生成订单ID
     * 格式：ORD + 实时年月日(8位) + 机器ID(2位) + 时间戳(6位) + 序列号(3位)
     */
    public String generateOrderId() {
        return generateId(ORDER_PREFIX);
    }

    /**
     * 生成退款ID
     * 格式：REF + 实时年月日(8位) + 机器ID(2位) + 时间戳(6位) + 序列号(3位)
     */
    public String generateRefundId() {
        return generateId(REFUND_PREFIX);
    }

    /**
     * 核心生成方法
     */
    private String generateId(String prefix) {
        lock.lock();
        try {
            long currentTimestamp = System.currentTimeMillis();
            // 获取当前实时日期字符串
            String currentDateStr = DATE_FORMAT.format(new Date(currentTimestamp));

            // 处理跨天情况：如果日期变了，重置序列号
            if (!currentDateStr.equals(lastDateStr)) {
                sequence = 0;
                lastDateStr = currentDateStr;
            }
            // 同一毫秒内，序列号自增
            else if (currentTimestamp == lastTimestamp) {
                sequence++;
                // 序列号超过最大值，等待下一毫秒
                if (sequence > 999) {
                    currentTimestamp = waitForNextMillis(currentTimestamp);
                    sequence = 0;
                }
            }
            // 不同毫秒，重置序列号
            else {
                sequence = 0;
            }

            lastTimestamp = currentTimestamp;

            // 处理时间部分：当天的秒数（0-86399），转为6位数字
            Calendar calendar = Calendar.getInstance();
            calendar.setTimeInMillis(currentTimestamp);
            int secondsOfDay = calendar.get(Calendar.HOUR_OF_DAY) * 3600
                    + calendar.get(Calendar.MINUTE) * 60
                    + calendar.get(Calendar.SECOND);
            String timePart = String.format("%06d", secondsOfDay);

            // 机器ID转为2位数字
            String machinePart = String.format("%02d", machineId);

            // 序列号转为3位数字
            String sequencePart = String.format("%03d", sequence);

            // 组合生成ID
            return prefix + currentDateStr + machinePart + timePart + sequencePart;
        } finally {
            lock.unlock();
        }
    }

    /**
     * 等待到下一毫秒
     */
    private long waitForNextMillis(long currentTimestamp) {
        long timestamp = currentTimestamp;
        while (timestamp <= currentTimestamp) {
            timestamp = System.currentTimeMillis();
        }
        return timestamp;
    }

    // 测试方法
    public static void main(String[] args) throws InterruptedException {
        DynamicDateOrderRefundIdGenerator generator = new DynamicDateOrderRefundIdGenerator(3);

        System.out.println("订单ID示例（包含实时创建日期）：");
        for (int i = 0; i < 3; i++) {
            System.out.println(generator.generateOrderId());
            Thread.sleep(500); // 间隔500毫秒生成一个
        }

        System.out.println("\n退款ID示例（包含实时创建日期）：");
        for (int i = 0; i < 3; i++) {
            System.out.println(generator.generateRefundId());
            Thread.sleep(500); // 间隔500毫秒生成一个
        }
    }
}
